//
// ast.h
// the ast for Potion code in-memory
//
// (c) 2008 why the lucky stiff, the freelance professor
//
#ifndef POTION_AST_H
#define POTION_AST_H

// 未使用 typedef struct {
//   PN v;
//   PN b;
// } PNArg;

enum PN_AST {
  AST_CODE,     // 程序(语句的元组，可空，末句后的逗号或换行可无)
  AST_VALUE,    // nil//bool//num//str//括号成对出现的utf8序列
  AST_ASSIGN,
  AST_NOT,      // expr
  AST_OR,
  AST_AND,
  AST_CMP,
  AST_EQ,
  AST_NEQ,
  AST_GT,
  AST_GTE,
  AST_LT,
  AST_LTE,
  AST_PIPE,
  AST_CARET,
  AST_AMP,
  AST_WAVY,     // expr
  AST_BITL,
  AST_BITR,
  AST_PLUS,
  AST_MINUS,
  AST_INC,      // --a:a_-2//++a:a_2//a++:a_3//a--:a_-1
  AST_TIMES,
  AST_DIV,
  AST_REM,
  AST_POW,
  AST_MESSAGE,  // utfw+?_参数[表]?_block?
  AST_PATH,     // utfw+_参数[表]?_block?
  AST_QUERY,    // utfw+_参数[表]?_block?
  AST_PATHQ,    // utfw+_参数[表]?_block?
  AST_EXPR,     // 元组，首项是表达式，后续是可能的消息
  AST_TABLE,    // table//lick(tuple类型，可空)
  AST_BLOCK,    // block
  AST_LICK,     // lick-item(末项后的逗号或换行可无，1-3个参数):name_inner?_attr?
  AST_PROTO     // 参数表?_block//block
};

// 未使用 #define PN_TOK_MISSING 0x10000

// 创建单参数 PNSource 。
#define PN_AST1(T, A)  potion_source(P, T, A, PN_NIL, PN_NIL)
// 全局搜索找不到，所以废弃
// #define PN_AST1(T, A)  potion_source(P, AST_##T, A, PN_NIL, PN_NIL)
// 创建双参数 PNSource 。
#define PN_AST2(T, A, B)  potion_source(P, T, A, B, PN_NIL)
// #define PN_AST2(T, A, B)  potion_source(P, AST_##T, A, B, PN_NIL)
// PN_OP -> PN_AST2 ，因与 opcode 中的 typedef struct PN_OP 重名。
// #define PN_OP(T, A, B)    potion_source(P, T, A, B, PN_NIL)
// 创建三参数 PNSource 。
#define PN_AST3(T, A, B, C)  potion_source(P, T, A, B, C)
// #define PN_AST3(T, A, B, C)  potion_source(P, AST_##T, A, B, C)
// 取 PNSource S 的分类字段 .type 。
#define PN_AST_TYPE(S)  ((struct PNSource *)S)->type
// 取 PNSource S 的索引 N 处的参数项。
#define PN_AST_ARG(S, N)    ((struct PNSource *)S)->a[N]
/* 未使用
#define PN_CLOSE(B) ({ \
    PN endname = B; \
    if (PN_IS_TUPLE(endname)) endname = PN_TUPLE_AT(endname, 0); \
    if (endname != PN_NIL) { \
      if (PN_AST_TYPE(endname) == AST_EXPR) endname = PN_TUPLE_AT(PN_AST_ARG(endname, 0), 0); \
      if (PN_AST_TYPE(endname) == AST_MESSAGE || PN_AST_TYPE(endname) == AST_PATH) \
        endname = PN_AST_ARG(endname, 0); \
      if (P->unclosed == endname) { P->unclosed = PN_NIL; } \
    } \
  })
  */

PN potion_source(Potion *P, u8 p, PN a, PN b, PN c);

#endif
